﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Data;
using System.Linq;
using System.Text;
using System.Windows.Forms;

namespace Constructor
{
    public partial class Field : UserControl
    {
        private int _rank;
        public struct Coord
        {
            public int x;
            public int y;
        }
        public Field()
        {
            InitializeComponent();
            SetStyle(ControlStyles.Opaque | ControlStyles.OptimizedDoubleBuffer | ControlStyles.AllPaintingInWmPaint, true);           
        }
        public void Init()
        {
            Frame field = External.SearchFrame("Поле");
            _rank = (int)Math.Sqrt(field.Slots.Count());
            table.RowCount = _rank;
            table.ColumnCount = _rank;
            table.ColumnStyles.Clear();
            table.RowStyles.Clear();
            for (int i = 0; i < _rank; i++)
            {
                this.table.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, (float)100 / _rank));
                this.table.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, (float)100 / _rank));
            }
            LoadExemplars(MLO.MLOSource.Exemplars);
        }
        public void LoadExemplars(List<Frame> frames)
        {
            table.Controls.Clear();
            List<Frame> remove = new List<Frame>();
            foreach (Frame frame in frames)
                if (External.Parents.ContainsKey(frame.ID) && (External.Parents[frame.ID].Name == "Клетка" || External.Parents[frame.ID].Name == "Поле") || !External.Parents.ContainsKey(frame.ID))
                    remove.Add(frame);
            foreach (Frame frame in remove)
                frames.Remove(frame);
            remove.Clear();
            CreateCellExemplars();
            foreach (Frame frame in frames)
            {
                if (External.Parents.ContainsKey(frame.ID) && External.Parents[frame.ID].Name != "Поле" && frame.GetPositionSlot() != null)
                {
                    Coord coord = GetCoordByCell(frame.GetPositionSlot().Subframe);
                    frame.GetPositionSlot().Subframe = GetCellByCoord(coord);
                    if (!(coord.x >= _rank || coord.y >= _rank))
                    {
                        CreateFieldItem(frame, coord.x, coord.y);
                        if (!UpdateSlots(frame))
                            remove.Add(frame);
                    }
                    else
                        remove.Add(frame);
                    frame.GetSlots(External.SearchFrame("Клетка")).ForEach(o => o.Subframe = GetCellByCoord(GetCoordByCell(o.Subframe)));
                }
            }
            foreach (Frame frame in remove)
                frames.Remove(frame);
        }

        private bool UpdateSlots(Frame frame)
        {
            Frame prototype = null;
            if (External.Parents.ContainsKey(frame.ID) && External.SearchFrame(External.Parents[frame.ID].ID) != null)
                prototype = External.SearchFrame(External.Parents[frame.ID].ID);
            else
                return false;
            List<Slot> remove = new List<Slot>();
            foreach (Slot slot in frame.Slots)
                if (prototype.SearchInAllSlot(slot.Name) == null) remove.Add(slot);
            foreach (Slot slot in prototype.Slots)
                if (frame.SearchSlot(slot.Name) == null)
                    External.AddSlotToExem(frame, slot);
                else
                {
                    Slot s = frame.SearchSlot(slot.Name);
                    if (!s.Equals(slot))
                    {
                        remove.Add(s);
                        External.AddSlotToExem(frame, slot);
                    }
                }
            foreach (Slot slot in remove)
                frame.Slots.Remove(slot);
            return true;
        }
        public Coord GetCoordByCell(Frame f)
        {
            Coord c;
            int.TryParse(f.SearchSlot("X").Default.ToString(), out c.x);
            int.TryParse(f.SearchSlot("Y").Default.ToString(), out c.y);
            return c;
        }
        public Frame GetCellByCoord(int x, int y)
        {
            List<Frame> frames = MLO.MLOSource.Exemplars;
            foreach (Frame f in frames)
                if (External.Parents.ContainsKey(f.ID) && External.Parents[f.ID].Name == "Клетка")
                {
                    Slot sx = f.SearchSlot("X");
                    Slot sy = f.SearchSlot("Y");
                    if (sx.Default.ToString() == x.ToString() && sy.Default.ToString() == y.ToString())
                        return f;
                }
            return null;
        }
        public Frame GetCellByCoord(Coord coord)
        {
            List<Frame> frames = MLO.MLOSource.Exemplars;
            foreach (Frame f in frames)
                if (External.Parents.ContainsKey(f.ID) && External.Parents[f.ID].Name == "Клетка")
                {
                    Slot sx = f.SearchSlot("X");
                    Slot sy = f.SearchSlot("Y");
                    if (sx.Default.ToString() == coord.x.ToString() && sy.Default.ToString() == coord.y.ToString())
                        return f;
                }
            return null;
        }
        public void CreateCellExemplars()
        {
            Frame ex_field = External.GetExemplarByPrototype(External.SearchFrame("Поле"));
            for (int i = 0; i < _rank; i++)
                for (int j = 0; j < _rank; j++)
                {
                    Frame cell = External.GetExemplarByPrototype(External.SearchFrame("Клетка"));
                    ex_field.Slots[i * _rank + j].Subframe = cell;
                    if (cell != null)
                    {
                        Slot x = cell.SearchSlot("X");
                        Slot y = cell.SearchSlot("Y");
                        cell.Name = "Клетка[" + i.ToString() + "," + j.ToString() + "]";
                        if (x != null) x.Default = i;
                        if (y != null) y.Default = j;
                    }
                }
        }
        public void SetCell(Frame exem, Frame cell)
        {
            if (exem.GetPositionSlot() != null && cell != null && exem.GetPositionSlot().Subframe != cell)
                exem.GetPositionSlot().Subframe = cell;
        }
        public void CreateFieldItem(Frame exem, int row, int column)
        {
            FieldItem item = new FieldItem(exem);
            SetCell(exem, GetCellByCoord(row, column));
            item.Click += new EventHandler(item_Click);
            item.Frame.FieldItem = item;
            item.Dock = DockStyle.Fill;
            if (table.GetControlFromPosition(column, row) == null)
                table.Controls.Add(item, column, row);
        }
        private void table_DragDrop(object sender, DragEventArgs e)
        {
            table.SuspendLayout();
            Frame f = e.Data.GetData(typeof(Frame)) as Frame;
            if (f != null)
            {
                Point p = table.PointToClient(MousePosition);
                int row = (int)(p.Y / ((float)table.Height / _rank));
                int column = (int)(p.X / ((float)table.Width / _rank));
                CreateFieldItem(External.GetExemplarByPrototype(f), row, column);
            }
            else
            {
                FieldItem item = e.Data.GetData(typeof(FieldItem)) as FieldItem;
                Point p = table.PointToClient(MousePosition);
                int row = (int)(p.Y / ((float)table.Height / _rank));
                int column = (int)(p.X / ((float)table.Width / _rank));
                item.Move(row, column);
            }
            table.ResumeLayout();
        }
        FieldItem active = null;
        void item_Click(object sender, EventArgs e)
        {
            SuspendLayout();

            if (active != null)
                active.Active = false;
            (sender as FieldItem).Active = true;
            active = sender as FieldItem;
            ResumeLayout(false);
            BackgroundWorker worker = new BackgroundWorker();
            worker.DoWork += new DoWorkEventHandler(worker_DoWork);
            worker.RunWorkerAsync();
            
        }

        void worker_DoWork(object sender, DoWorkEventArgs e)
        {
            BeginInvoke((Action)delegate()
            {
                External.exemplars.exemplarProperties.Init(active.Frame);
            });
        }

        private void table_DragEnter(object sender, DragEventArgs e)
        {
            e.Effect = DragDropEffects.All;
        }
    }
}
